package com.printeverywhere.util;

import com.sun.image.codec.jpeg.JPEGImageEncoder;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;

import javax.imageio.ImageIO;
import javax.swing.*;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.Kernel;
import java.awt.image.ConvolveOp;

public class ImageUtil {

    public static void resize(File originalFile, File resizedFile, int newWidth, float quality) throws IOException {

        if (quality < 0 || quality > 1) {
            throw new IllegalArgumentException("Quality has to be between 0 and 1");
        }

        ImageIcon ii = new ImageIcon(originalFile.getCanonicalPath());
        Image i = ii.getImage();
        Image resizedImage = null;

        int iWidth = i.getWidth(null);
        int iHeight = i.getHeight(null);

        if (iWidth > iHeight) {
            resizedImage = i.getScaledInstance(newWidth, (newWidth * iHeight) / iWidth, Image.SCALE_SMOOTH);
        } else {
            resizedImage = i.getScaledInstance((newWidth * iWidth) / iHeight, newWidth, Image.SCALE_SMOOTH);
        }

        // This code ensures that all the pixels in the image are loaded.
        Image temp = new ImageIcon(resizedImage).getImage();

        // Create the buffered image.
        BufferedImage bufferedImage = new BufferedImage(temp.getWidth(null), temp.getHeight(null),
                                                        BufferedImage.TYPE_INT_RGB);

        // Copy image to buffered image.
        Graphics g = bufferedImage.createGraphics();

        // Clear background and paint the image.
        g.setColor(Color.white);
        g.fillRect(0, 0, temp.getWidth(null), temp.getHeight(null));
        g.drawImage(temp, 0, 0, null);
        g.dispose();

        // Soften.
        float softenFactor = 0.05f;
        float[] softenArray = {0, softenFactor, 0, softenFactor, 1-(softenFactor*4), softenFactor, 0, softenFactor, 0};
        Kernel kernel = new Kernel(3, 3, softenArray);
        ConvolveOp cOp = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
        bufferedImage = cOp.filter(bufferedImage, null);

        // Write the jpeg to a file.
        FileOutputStream out = new FileOutputStream(resizedFile);

        // Encodes image as a JPEG data stream
        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);

        JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bufferedImage);

        param.setQuality(quality, true);

        encoder.setJPEGEncodeParam(param);
        encoder.encode(bufferedImage);
    }
    /**
     * This method takes in an image as a byte array (currently supports GIF, JPG, PNG and possibly other formats) and
     * resizes it to have a width no greater than the pMaxWidth parameter in pixels. It converts the image to a standard
     * quality JPG and returns the byte array of that JPG image.
     *
     * @param pImageData
     *                the image data.
     * @param pMaxWidth
     *                the max width in pixels, 0 means do not scale.
     * @return the resized JPG image.
     * @throws IOException
     *                 if the iamge could not be manipulated correctly.
     */
    public static byte[] resizeImageAsJPG(byte[] pImageData, int pMaxWidth, int pMaxHeight, String imgExtension)
			throws IOException {
		// Create an ImageIcon from the image data
		ImageIcon imageIcon = new ImageIcon(pImageData);

		// Create a new empty image buffer to "draw" the resized image into
		BufferedImage bufferedResizedImage = new BufferedImage(pMaxWidth, pMaxHeight,
				BufferedImage.TYPE_INT_RGB);
		// Create a Graphics object to do the "drawing"
		Graphics2D g2d = bufferedResizedImage.createGraphics();
		g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
				RenderingHints.VALUE_INTERPOLATION_BICUBIC);
		// Draw the resized image
		g2d.drawImage(imageIcon.getImage(), 0, 0, pMaxWidth, pMaxHeight, null);
		g2d.dispose();
		// Now our buffered image is ready
		// Encode it as a JPEG
		ByteArrayOutputStream encoderOutputStream = new ByteArrayOutputStream();
		ImageIO.write(bufferedResizedImage, imgExtension, encoderOutputStream);

		byte[] resizedImageByteArray = encoderOutputStream.toByteArray();
		return resizedImageByteArray;
	}
    public BufferedImage resizeByWidth(BufferedImage image, int maxWidth) {
        double w = image.getWidth(null);
        double h = image.getHeight(null);
        int width = maxWidth;
        int height = (int) ((h / w) * maxWidth);
        return resizeTo(image, width, height);
    }

    public static BufferedImage resizeByWidthHeight(byte[] pImageData, BufferedImage image, int maxWidth, int maxHeight) {
    	ImageIcon imageIcon = new ImageIcon(pImageData);
//		int width = imageIcon.getIconWidth();
//		int height = imageIcon.getIconHeight();
//    	BufferedImage bufferedImage = new BufferedImage(width, height)
    	double w = image.getWidth(null);
        double h = image.getHeight(null);
        int width = (int) ((w / h) * maxHeight);
        int height = (int) ((h / w) * maxWidth);
        return resizeTo(image, width, height);
    }


    public BufferedImage resizeByHeight(BufferedImage image, int maxHeight) {
        double w = image.getWidth(null);
        double h = image.getHeight(null);
        int width = (int) ((w / h) * maxHeight);
        int height = maxHeight;
        return resizeTo(image, width, height);
    }

    public static BufferedImage resizeTo(BufferedImage image, int width, int height) {
        return toBufferedImage(image.getScaledInstance(width, height, Image.SCALE_SMOOTH));
    }
    protected static BufferedImage toBufferedImage(Image image) {
        if (image instanceof BufferedImage) {
            return (BufferedImage)image;
        }

        // This code ensures that all the pixels in the image are loaded
        image = new ImageIcon(image).getImage();

        // Create a buffered image with a format that's compatible with the screen
        BufferedImage bimage = null;
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        try {
            // Determine the type of transparency of the new buffered image
            int transparency = Transparency.OPAQUE;

            // Create the buffered image
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = gs.getDefaultConfiguration();
            bimage = gc.createCompatibleImage(
                image.getWidth(null), image.getHeight(null), transparency);
        } catch (HeadlessException e) {
            // DO NOTHING
        }

        if (bimage == null) {
            // Create a buffered image using the default color model
            int type = BufferedImage.TYPE_INT_RGB;
            bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
        }

        // Copy image to buffered image
        Graphics g = bimage.createGraphics();

        // Paint the image onto the buffered image
        g.drawImage(image, 0, 0, null);
        g.dispose();

        return bimage;
    }
 // Example usage
    public static void main(String[] args) throws IOException {
        File originalImage = new File("/home/username/images/img.jpg");
        resize(originalImage, new File("/home/username/images/img-resized-350-quality-0.7.jpg"), 350, 0.7f);
        resize(originalImage, new File("/home/username/images/img-resized-350-quality-1.jpg"), 350, 1f);
    }

}